package sunyu.controller.quartz;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Record;
import org.quartz.*;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import sunyu.controller.common.CommonController;
import sunyu.kit.common.LogKit;
import sunyu.kit.database.DataBaseKit;
import sunyu.quartz.common.config.QuartzDataBaseKitInit;

import javax.annotation.Resource;
import java.util.*;

/**
 * 定时任务
 *
 * @author 孙宇
 */
@Controller
@RequestMapping("/quartz")
public class QuartzController extends CommonController {

    private static final Logger logger = LogKit.getLogger();

    @Resource(name = "schedulerFactoryBean")
    private StdScheduler scheduler;

    private Dao dao = DataBaseKit.getDao(QuartzDataBaseKitInit.quartzDataBase);

    /**
     * 列出所有任务
     *
     * @param model
     * @return
     */
    @RequestMapping("/list")
    @RequiresAuthentication//验证是否登录，等同于subject.isAuthenticated()
    @RequiresPermissions(value = {"quartz:list"}, logical = Logical.AND)//验证是否有权限
    public String list(Model model) {
        String schedulerName = scheduler.getSchedulerName();
        List<Map<String, Object>> jobs = new ArrayList<>();
        try {
            for (String jobGroupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroupName))) {
                    String jobName = jobKey.getName();
                    String jobGroup = jobKey.getGroup();
                    List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        TriggerKey triggerKey = trigger.getKey();
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
                        String triggerStateName = null;
                        switch (triggerState.name()) {
                            case "PAUSED":
                                triggerStateName = "任务暂停";
                                break;
                            case "NORMAL":
                                triggerStateName = "等待执行";
                                break;
                            case "BLOCKED":
                                triggerStateName = "正在执行";
                                break;
                            default:
                                triggerStateName = triggerState.name();
                                break;
                        }
                        Map<String, Object> job = new HashMap<>();
                        job.put("triggerName", triggerKey.getName());
                        job.put("triggerGroup", triggerKey.getGroup());
                        job.put("jobGroup", jobGroup);
                        job.put("jobName", jobName);
                        job.put("startTime", trigger.getStartTime());
                        job.put("nextFireTime", trigger.getNextFireTime());
                        job.put("previousFireTime", trigger.getPreviousFireTime());
                        job.put("triggerState", triggerStateName);
                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            String cronExpression = cronTrigger.getCronExpression();
                            job.put("cronExpression", cronExpression);
                        }
                        Record result = dao.fetch("QRTZ_FIRED_TRIGGERS", Cnd.where("SCHED_NAME", "=", schedulerName).and("TRIGGER_GROUP", "=", triggerKey.getGroup()).and("TRIGGER_NAME", "=", triggerKey.getName()));
                        if (result != null) {
                            String host = result.getString("INSTANCE_NAME");
                            job.put("executionHost", host.substring(0, host.length() - 13));//后13位是随机数
                        } else {
                            job.put("executionHost", "");
                        }
                        job.put("schedulerName", schedulerName);
                        jobs.add(job);
                    }
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        Collections.sort(jobs, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1,
                               Map<String, Object> o2) {
                if (o1.get("nextFireTime") != null && o2.get("nextFireTime") != null) {
                    if (o1.get("nextFireTime") instanceof Date && o2.get("nextFireTime") instanceof Date) {
                        Date d1 = (Date) o1.get("nextFireTime");
                        Date d2 = (Date) o2.get("nextFireTime");
                        return d1.compareTo(d2);
                    }
                }
                return String.valueOf(o1.get("nextFireTime")).compareTo(String.valueOf(o2.get("nextFireTime")));
            }
        });
        model.addAttribute("jobs", jobs);
        return "/quartz/list";
    }


    /**
     * 操作任务
     *
     * @param jobGroup
     * @param jobName
     * @return
     */
    @RequestMapping("/{action}")
    @RequiresAuthentication//验证是否登录，等同于subject.isAuthenticated()
    @RequiresPermissions(value = {"quartz:action"}, logical = Logical.AND)//验证是否有权限
    public String execute(@PathVariable(value = "action") String action,
                          @RequestParam(value = "jobGroup", required = false) String jobGroup,
                          @RequestParam(value = "jobName", required = false) String jobName) {
        try {
            if (action.equals("pauseAll")) {
                scheduler.pauseAll();
            } else if (action.equals("resumeAll")) {
                scheduler.resumeAll();
            } else {
                JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
                switch (action) {
                    case "delete":
                        scheduler.deleteJob(jobKey);
                        break;
                    case "resume":
                        scheduler.resumeJob(jobKey);
                        break;
                    case "pause":
                        scheduler.pauseJob(jobKey);
                        break;
                    case "trigger":
                        scheduler.triggerJob(jobKey);
                        break;
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "redirect:/quartz/list";
    }

    /**
     * 更新任务启动时间
     *
     * @param triggerGroup
     * @param triggerName
     * @param cronExpression
     * @return
     */
    @RequestMapping("/updateCronExpression")
    @RequiresAuthentication//验证是否登录，等同于subject.isAuthenticated()
    @RequiresPermissions(value = {"quartz:updateCronExpression"}, logical = Logical.AND)//验证是否有权限
    public String updateCronExpression(@RequestParam(value = "triggerGroup", required = false) String triggerGroup,
                                       @RequestParam(value = "triggerName", required = false) String triggerName,
                                       @RequestParam(value = "cronExpression", required = false) String cronExpression) {
        if (CronExpression.isValidExpression(cronExpression)) {
            TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroup);
            if (triggerKey != null) {
                try {
                    Trigger trigger = scheduler.getTrigger(triggerKey);
                    if (trigger != null) {
                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            String oldCronExpression = cronTrigger.getCronExpression();
                            if (!oldCronExpression.equalsIgnoreCase(cronExpression)) {
                                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                                triggerBuilder.withIdentity(triggerName, triggerGroup);
                                triggerBuilder.startNow();
                                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));
                                scheduler.rescheduleJob(triggerKey, triggerBuilder.build());
                            }
                        }
                    }
                } catch (SchedulerException e) {
                }
            }
        }
        return "redirect:/quartz/list";
    }

}
